/* * Copyright 2015 Nicolas Morel * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.nmorel.gwtjackson.rest.processor; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HEAD; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * @author Nicolas Morel */ public class RestService { private final TypeElement typeElement; private final String packageName; private final String builderClassName; private final List<RestServiceMethod> methods = new ArrayList<RestServiceMethod>(); private final Map<ExecutableElement, Exception> methodsInError = new HashMap<ExecutableElement, Exception>(); private final Set<TypeMirror> returnTypes = new LinkedHashSet<TypeMirror>(); private final Set<TypeMirror> bodyTypes = new LinkedHashSet<TypeMirror>(); public RestService( Options options, Element element ) { // only types can be annotated with @GenRestService so it's safe to cast into TypeElement typeElement = (TypeElement) element; if ( null == options.getPackageName() ) { Element enclosingElement = typeElement.getEnclosingElement(); while ( ElementKind.PACKAGE != enclosingElement.getKind() ) { enclosingElement = enclosingElement.getEnclosingElement(); } PackageElement packageElement = (PackageElement) enclosingElement; packageName = packageElement.getQualifiedName().toString(); } else { packageName = options.getPackageName(); } builderClassName = typeElement.getSimpleName().toString() + "Builder"; Path path = typeElement.getAnnotation( Path.class ); String baseRestUrl = path.value(); for ( ExecutableElement method : ElementFilter.methodsIn( typeElement.getEnclosedElements() ) ) { parseMethod( baseRestUrl, method ); } } private void parseMethod( String baseRestUrl, ExecutableElement method ) { AnnotationMirror httpMethodAnnotation = isRestMethod( method ); if ( null == httpMethodAnnotation ) { // not a rest method return; } TypeMirror returnType = null; if ( TypeKind.VOID != method.getReturnType().getKind() ) { if ( method.getReturnType().toString().equals( Response.class.getName() ) ) { GenResponseClassType ann = method.getAnnotation( GenResponseClassType.class ); if ( ann != null ) { try { ann.value(); methodsInError.put( method, new IllegalArgumentException( "Cannot read class from annotation " + ann ) ); } catch ( MirroredTypeException mte ) { returnType = mte.getTypeMirror(); } } else { methodsInError.put( method, new MissingGenResponseClassTypeException( method ) ); } } else { returnType = method.getReturnType(); } } RestServiceMethod restServiceMethod; try { restServiceMethod = new RestServiceMethod( method, baseRestUrl, httpMethodAnnotation, returnType ); } catch ( Exception e ) { methodsInError.put( method, e ); return; } methods.add( restServiceMethod ); if ( null != returnType ) { returnTypes.add( returnType ); } if ( null != restServiceMethod.getBodyParamVariable() ) { bodyTypes.add( restServiceMethod.getBodyParamVariable().asType() ); } } /** * Check if the method is a REST method. If the method has a HTTP method annotation like {@link GET} and is not ignored with {@link * GenRestIgnore} then it's a REST method. * * @param method the method to check * * @return the HTTP method annotation found or null if the method is not a REST method or is ignored */ private AnnotationMirror isRestMethod( ExecutableElement method ) { AnnotationMirror httpMethod = null; for ( AnnotationMirror m : method.getAnnotationMirrors() ) { if ( m.getAnnotationType().toString().equals( GenRestIgnore.class.getName() ) ) { return null; } if ( m.getAnnotationType().toString().equals( GET.class.getName() ) ) { httpMethod = m; } else if ( m.getAnnotationType().toString().equals( POST.class.getName() ) ) { httpMethod = m; } else if ( m.getAnnotationType().toString().equals( PUT.class.getName() ) ) { httpMethod = m; } else if ( m.getAnnotationType().toString().equals( DELETE.class.getName() ) ) { httpMethod = m; } else if ( m.getAnnotationType().toString().equals( HEAD.class.getName() ) ) { httpMethod = m; } } return httpMethod; } public TypeElement getTypeElement() { return typeElement; } public String getPackageName() { return packageName; } public String getBuilderSimpleClassName() { return builderClassName; } public String getBuilderQualifiedClassName() { return packageName + "." + builderClassName; } public List<RestServiceMethod> getMethods() { return methods; } public Map<ExecutableElement, Exception> getMethodsInError() { return methodsInError; } public Set<TypeMirror> getReturnTypes() { return returnTypes; } public Set<TypeMirror> getBodyTypes() { return bodyTypes; } }